﻿/********************************************************************************
** @ Date:2023/02/01
** @ Author: Gaojia
** @ Description:  QModbus 工作类
** @ Version:1.0.0
** @ Fun:
********************************************************************************/

/**
* @ Author: Gaojia 20240131
* @ Description: 注释: 这个类可能有点小bug 等有空修改 先完成主体程序
*/
#ifndef CModBusOper_H
#define CModBusOper_H


#include "Header.h"

#define READSLEEP 200
#define WRITESLEEP  200
class CModBusOper :public QObject
{
	Q_OBJECT
public:
	CModBusOper(QString sIp, int nPort, int nDateType = 3);   //数据类型 默认为3  
	void setSlaveId(int nId);                                 //设置从站号
	~CModBusOper();
	bool ReadVal(int nAddr, int &);                         //读单个地址寄存器值
	bool ReadVal(int nAddr, int nLength, int &);            //读多个寄存器地址拼成一个值
	bool ReadValEx(int nAddr, int nLength, QVector<int>&);   //读多个机器人地址值
	bool WriteVal(int nAddr, int);                          //写一个地址值
	bool WriteValCoil(int nAddr, int);                      //写一个线圈地址值
	bool WriteVal(int nAddr, int nLength, int);              //一个值分成多个寄存器地址写值 
	bool WriteValEx(int nAddr, int nLength, QVector<int>);  //写多个地址值
	QString GerReError();                                   //获取失败返回字符串
	bool m_bModConnect;                                     //Modbus 是否连接成功                              

private:
	void InitMod();    //初始化modbus
	bool ReadValsOperEx(int nAddr, int nLength);
	bool WriteValsOperEx(int nAddr, int nLength, QVector<int>);
	bool ReadValsOper(int nAddr, int nLength);
	bool WriteValsOper(int nAddr, int nLength, QVector<int>);
	void SleepSysMs(int nMs);    //休眠多少毫秒
	void ThreadReadVal();        //线程读取数据
	void ThreadWriteVal();        //线程写数据
	void ThreadReadValEx();        //线程读取数据
	void ThreadWriteValEx();        //线程写数据
	void ResetData();             //复位数据
	QVector<int> GetReadVal();
	void SetWriteVal(QVector<int>vecVal);
	void SetReError(QString sReError);
protected:
	void timerEvent(QTimerEvent * event)override;
private:
	QString m_sIp;
	int m_nPort;
	int m_nDateType;   //数据类型   1 线圈 3  读写寄存器
	QThread *m_pExecThread;
	QModbusTcpClient *m_pModTcp; //ModbusTCP客户端对象
	QVector<int> m_vecReadVal;
	QString m_sReError;          //返回的错误信息
	bool m_bGood;                //读数据或者写数据成功或失败
	QMutex *m_pMutex;            //资源锁  对外是线程安全的
	QMutex *m_pMutexDate;        //数据锁  
	QMutex *m_pSysMutex;          //现场同步锁
	QWaitCondition *m_pWaitCondition;   //线程同步信号
	int m_nConnectTimer;     //获取设备数据定时器
	bool      m_bThread;         //异步线程状态
	bool WaitSys(int nSystime);   //现场同步阻塞nSystime毫秒
private:
	int m_nThreadCmd;            //线程工作命令    0 无操作  1读数据  2 写数据  3处理数据
	int m_nAddr;   //地址
	int m_nLength; //长度
	QVector<int>m_vecWriteVal;  //写入的数据
	int m_nSlaveId;   //从站Id
	int m_nDisConnect;
	bool m_bConnect;
private slots:
	void slot_ReadVal(QModbusReply *reply);
	void slot_WriteVal(QModbusReply *reply);
	void onStateChanged(int nState);
	void slot_ThreadWork();

};

#endif